package me.youline.dataServer.dao.socialActionMsg;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import me.youline.dataServer.entity.socialActionMsg.SocialActionBaseMsg;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

/**
 * 社交行为通知抽象DAO
 * 
 * @author linhan
 */
public abstract class AbstractSocialActionMsgDAO<T extends SocialActionBaseMsg> {

	@Autowired
	protected JdbcTemplate jdbcTemplate;

	@Autowired
	protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	/**
	 * 批量查询SQL
	 */
	private String QUERY_LIST_SQL = " select * from %s where id in(:ids)";

	/**
	 * 根据消息ID查询通知消息数据
	 */
	private String QUERY_SQL = "select * from  %s where id = ?";

	/**
	 * 根据通知消息ID删除数据
	 */
	private String DELETE_BY_ID_SQL = "delete from %s where id = ?";

	/**
	 * 根据条件查询
	 */
	private String QUERY_ID_BY_CONDITION_SQL = " select id from %s where 1=1 %s ";

	private SimpleJdbcInsert insertOperation;

	@PostConstruct
	private void init() {
		QUERY_LIST_SQL = String.format(QUERY_LIST_SQL, getTableName());
		QUERY_SQL = String.format(QUERY_SQL, getTableName());
		DELETE_BY_ID_SQL = String.format(DELETE_BY_ID_SQL, getTableName());
		QUERY_ID_BY_CONDITION_SQL = String.format(QUERY_ID_BY_CONDITION_SQL,
				getTableName(), "%s");// 需要后续继续格式化
		insertOperation = new SimpleJdbcInsert(jdbcTemplate).withTableName(
				getTableName()).usingGeneratedKeyColumns("id");
	}

	/**
	 * 批量获取社交通知消息
	 * 
	 * @param userId
	 *            通知用户ID
	 * @param page
	 *            分页对象
	 * @return
	 */
	public List<T> getSocailNotifications(Collection<Long> ids) {
		if (ids == null || ids.isEmpty()) {
			return Collections.emptyList();
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("ids", ids);
		return namedParameterJdbcTemplate.query(QUERY_LIST_SQL, map,
				this.getEntityInnerRowMapper());
	}
	
	/**
	 * 添加社交事件消息
	 * 
	 * @param msg
	 * @return
	 */
	public Long addSocialActionNotifyMsg(final T msg) {
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		map.put("initiator", msg.getInitiatorId());
		map.put("targetId", msg.getTargetId());
		map.put("createTime", msg.getCreateTime());
		map.put("notifiedUserId", msg.getNotifiedUserId());
		this.initMsgAddData(msg, map);
		return insertOperation.executeAndReturnKey(map).longValue();
	}

	/**
	 * 根据id获取社交事件消息
	 * 
	 * @param id
	 * @return
	 */
	public T getSocialActionMsgById(Long id) {
		try {
			return jdbcTemplate.queryForObject(QUERY_SQL, new Object[] { id },
					getEntityInnerRowMapper());
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}

	/**
	 * 根据查询条件实体获取消息ID
	 * @param builder
	 * @return 
	 */
	protected List<Long> getMsgIdsByCondition(ConditionBuilder builder) {
		return jdbcTemplate.queryForList(String.format(
				QUERY_ID_BY_CONDITION_SQL, builder.getConditionString()),
				builder.getConditionObjList().toArray(), Long.class);
	}
	
	/**
	 * 根据行为操作对象ID获取通知消息ID
	 * 
	 * @param targetId
	 * @return
	 */
	public List<Long> getMsgIdsByTargetId(Long targetId){
		ConditionBuilder builder = new ConditionBuilder();
		builder.addEqCondition("targetId", targetId);
		return this.getMsgIdsByCondition(builder);
	}

	/**
	 * 通过ID删除社交行为通知消息
	 * 
	 * @param id
	 * @return
	 */
	public int deleteSocialActionMsgById(Long id) {
		return jdbcTemplate.update(DELETE_BY_ID_SQL, new Object[] { id });
	}
	
	/**
	 * 根据id集合批量删除通知消息
	 * @param ids
	 * @return
	 */
	public int batchDeleteSocialActionMsgById(List<Long> ids) {
		List<Object[]> args = new ArrayList<Object[]>();
		for(Long id : ids){
			args.add(new Object[]{id});
		}
		int[] r =  jdbcTemplate.batchUpdate(DELETE_BY_ID_SQL, args);
		int res = 0;
		for(int i : r){
			res += i;
		}
		return res;
	}

	/**
	 * 初始化消息实体添加的映射数据
	 * @param msg
	 * @param map
	 */
	abstract protected void initMsgAddData(final T msg, Map<String, Object> map);

	/**
	 * 获取数据库表名
	 * @return
	 */
	abstract protected String getTableName();

	/**
	 * 获取实体与数据行映射关系
	 * @return
	 */
	abstract protected RowMapper<T> getEntityInnerRowMapper();

	protected static abstract class SocialActionMsgRowMapper<M extends SocialActionBaseMsg>
			implements RowMapper<M> {

		private final M msg;

		public SocialActionMsgRowMapper(M msg) {
			this.msg = msg;
		}

		/**
		 * 子类可以覆盖该方法，编写自己特殊列的映射 
		 * */
		@SuppressWarnings("unchecked")
		@Override
		public M mapRow(ResultSet rs, int rowNum) throws SQLException {
			M copy;
			try {
				copy = (M) BeanUtils.cloneBean(msg);
			} catch (IllegalAccessException | InstantiationException
					| InvocationTargetException | NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
			copy.setId(rs.getLong("id"));
			copy.setCreateTime(rs.getTimestamp("createTime"));
			copy.setInitiatorId(rs.getLong("initiator"));
			copy.setTargetId(rs.getLong("targetId"));
			copy.setNotifiedUserId(rs.getLong("notifiedUserId"));
			doSpecialMapRow(copy, rs, rowNum);
			return copy;
		}
		
		abstract protected void doSpecialMapRow(M msg,ResultSet rs, int rowNum) throws SQLException;

	}

	/**
	 * SQL查询构建器
	 * 
	 * @author linhan
	 *
	 */
	protected static class ConditionBuilder {

		private Map<String, Object> map = new LinkedHashMap<String, Object>();

		private String conditionStr;

		private List<Object> list;

		public void addEqCondition(String name, Object value) {
			if (value != null) {
				map.put(name, value);
			}
		}

		/**
		 * 获取条件语句
		 * 
		 * @return
		 */
		public String getConditionString() {
			if (!StringUtils.isBlank(conditionStr)) {
				return conditionStr;
			}
			StringBuilder builder = new StringBuilder();
			for (String name : map.keySet()) {
				builder.append(" and ");
				builder.append(name);
				builder.append(" = ");
				builder.append(" ? ");
			}
			return builder.toString();
		}

		/**
		 * 获取查询条件对象列表
		 * 
		 * @return
		 */
		public List<Object> getConditionObjList() {
			if (list != null) {
				return list;
			} else {
				list = new ArrayList<Object>();
				list.addAll(map.values());
				return list;
			}
		}
	}

}
